<?php

require_once eCMS_DIR . '/app/security/SecurityObject.class.php';
require_once eCMS_DIR . '/app/page/NestedPageSet.class.php';

require_once 'ToolBox.class.php';

class Page {
	
	//Request/Processing Information
	protected $allowedMethods; 
	
	/**
	 * Saves the Page request given by the PageFactory
	 *
	 * @var PageRequest
	 */
	protected $pageRequest;
	
	//Page Information
	protected $pkPage, $fkArea, $fkParentPage, $fkPageSecurityObject, $fkInstanceSecurityObject, $navTitle, $navPosition, $navImage, $isNavVisible, $parentPage, $subPages;
	private $isInPath;
	
	//NestedPages
	private $NestedPageSet, $fkNestedPageSet, $nestedPageMode;
	private $fkPageLayout, $fkPageLayoutName;
	
	//Design, Area related
	private $designName, $designNameOrig, $designMode;
	private $areaSwitches;
	
	//Module Information
	protected $fkModuleInstance, $moduleMethod, $params, $pkModule, $moduleName, $tablePostfix;
	
	//Security
	private   $PageSecurityObject;			//Security Object for Page Handling, Navigation, Change Navigation, Link to ModuleInstance, etc.
	protected $InstanceSecurityObject;		//Security Object wich Controls each Instance of the Page with this Type of Module
	protected $ItemSecurityObject;			//Security Object of an Item in a Instance of an Instance. For Example an PhotoAlbum in an Instance of the Module PhotoLibrary
	
	//Information about the Page to be overriden in the process
	protected  $pageText, $pageTitle, $pageCreateUser, $pageCreateDate, $pageChangeUser, $pageChangeDate;
	protected  $isPlainText; //If true, do not render the Page
	
	//Toolbox Items
	private $ItemToolbox, $InstanceToolbox, $ModuleToolbox, $PageToolbox, $SiteToolbox;
	
	//Data-Storage for the View
	protected $viewData;
	
	/*
	 * ================================================
	 * 				   MAIN FUNCTIONS
	 * 				   ---------------
	 * 
	 * ================================================
	 */
	
	
	// Basic Handling
	// ==============
	
	public function __construct($pkPage, Page $parentPage=null, $data=null) {

		$cfg = Runtime::getConfiguration();
		$conn = MySQLConnection::getInstance();
		
		//Initialize Vars
		$this->allowedMethods = array();
		$this->viewData = array();
		
		/**
		 * + 1. Load Information of tblPage into the Class
		 * + 2. Load SecurityObject of Page save it private in the Class
		 * - 3. Load all possible Methods (not based on current User-Privilegues) in $availableMethods
		 * 
		 */
		
		//Load Page Information
		//---------------------
		if(!$data) {
			$sql = "SELECT p.pkPage, p.fkArea, p.fkParentPage, p.fkModuleInstance, p.fkMethod, p.params, p.fkSecurityObject, mi.fkSecurityObject, p.fkCreateUser, p.createDate, 
						p.fkNestedPageSet, p.nestedPageMode, p.navTitle, p.sortId, p.navImage, p.pageTitle, p.isNavVisible, tablePostfix, m.pkModule, m.name, d.sysname, 
						p.fkPageLayout, pl.sysname AS  fkPageLayoutName
					FROM " . $cfg['table_prefix'] . "Page as p
					LEFT JOIN " . $cfg['table_prefix'] . "ModuleInstance as mi ON mi.pkModuleInstance = p.fkModuleInstance
					LEFT JOIN " . $cfg['table_prefix'] . "Module as m ON m.pkModule = mi.fkModule
					LEFT JOIN " . $cfg['table_prefix'] . "Area as a ON a.pkArea = p.fkArea
					LEFT JOIN " . $cfg['table_prefix'] . "Design as d ON d.pkDesign = a.fkDesign
					LEFT JOIN " . $cfg['table_prefix'] . "PageLayout as pl ON pl.pkPageLayout = p.fkPageLayout
			WHERE pkPage='$pkPage'";
					
			$data = $conn->quickQuery($sql);
		}
		else {
			//Load via $data, batch load---
		}
		
		list($this->pkPage, 
			 $this->fkArea, 
			 $this->fkParentPage, 
			 $this->fkModuleInstance, 
			 $this->moduleMethod,
			 $this->params,
			 $this->fkPageSecurityObject,
			 $this->fkInstanceSecurityObject,
			 $this->pageCreateUser,
			 $this->pageCreateDate,
			 $this->fkNestedPageSet,
			 $this->nestedPageMode, 
			 $this->navTitle, 
			 $this->sortId,
			 $this->navImage, 
			 $this->pageTitle, 
			 $this->isNavVisible,
			 $this->tablePostfix,
			 $this->pkModule,
			 $this->moduleName,
			 $this->designName,
			 $this->fkPageLayout,
			 $this->fkPageLayoutName) = $data;
		

		//Recursive Functions
		//-------------------
			 
		//Load Parentpage (and it's parent page, and ...) if not a specific parentPage is given
		if($parentPage == null) {
			//Load Parent Page
			
			//First, load all Parent-Pages, recursive eh!!!
			if($this->fkParentPage) { 
				$this->parentPage = new Page($this->fkParentPage); 
			}	 
			else {
				//this is the top page under the Area --> No recursion Anymore
				$IsRootPage = true;
			}
		}
		else {
			//User given Parent Page als Parent
			$this->parentPage = $parentPage;
		}
 		
		
		
		/*
		 * Due recoursivity (Line 117), we can be shure that there is a parent Page, or if not
		 * the current page ist a root-Page of the Area, in that case the Area (fkArea) is relevant
		 */
		
		
		//Load fkArea (can be set or not)
		if(!$this->fkArea) { 
			$this->fkArea = $this->parentPage->getFkArea();
		}
		
		
		
		//Load Security Object
		//--------------------
		
		if(!$this->fkPageSecurityObject) {
			
			//Get Parent's Security Object
			if(isset($IsRootPage) && $IsRootPage) {
				//Load it by Area
				$this->fkPageSecurityObject = $conn->quickQuery("SELECT fkSecurityObject FROM " . $cfg['table_prefix'] . "Area WHERE pkArea = '$this->fkArea'");
			}
			else {
				//Use this
				$this->fkPageSecurityObject = $this->parentPage->fkPageSecurityObject;
			}
			
			if(!$this->fkPageSecurityObject) {
				//No SecurityObject found...
				$this->fkPageSecurityObject = -1; 
				//TODO: Throw Error Message do not found of Security Object for Page
				trigger_error("PageSecurityObject not found for Page!");
			}
		}
		$this->loadSecurityObjects();		
		
		
		
		/*
		 * Possible Modes for the current Page
		 * 
		 * Mode		Description
		 * ----		-----------
		 * NULL		Use the Parents Page NestedPageSet with Layout
		 * Merge	Merges the Parent PageSet with the one of the current Page. The Layout is inherited, only specified Pages (defined in the Pageset of the current Page) will be replaced
		 * Include	Include to NestedPageSet of the Current Page in the layout of the parent page
		 * Own		New base Layout with NestedPages.
		 */
		
		$npsl = new NestedPageSetList();
		
		//Load NestedPageset
		if(!$this->nestedPageMode) {
			//Load Parent or Area
			if(isset($IsRootPage) && $IsRootPage) {
				//Get NestedPageSetting from Area
				$this->fkNestedPageSet = $conn->quickQuery("SELECT fkNestedPageSet FROM " . $cfg['table_prefix'] . "Area WHERE pkArea = '$this->fkArea'");

			}
			else {
				//Get NestedPage From ParentPage
				$this->fkNestedPageSet = $this->parentPage->getFkNestedPageSet();
				//$this->nestedPageMode = "Own";
			}
			
			$list = $npsl->getByPkNestedPageSet($this->fkNestedPageSet);
			if($list->count()) { 
				$this->NestedPageSet = $list->At(0);
				$this->nestedPageMode = "own";
			}
		}
		elseif($this->nestedPageMode=="none") {
			//Clear it, don't have to do more	
		}
		elseif($this->nestedPageMode=="own") {
			//Load new NestedPageSet
			$list = $npsl->getByPkNestedPageSet($this->fkNestedPageSet);
			$this->NestedPageSet = $list->At(0);
			
		}
		elseif($this->nestedPageMode=="include") {
			$list = $npsl->getByPkNestedPageSet($this->fkNestedPageSet);
			$this->NestedPageSet = $list->At(0);
			
		}
		elseif($this->nestedPageMode=="merge") {
			//Merge if we're not the root
			
			
			if (!isset($IsRootPage) || !$IsRootPage) {
				$list = $npsl->getByPkNestedPageSet($this->fkNestedPageSet);
				$this->NestedPageSet = $list->At(0);
				$pnps = $this->parentPage->getNestedPageSet();
				$this->NestedPageSet->merge($pnps);
				
				$this->nestedPageMode="own";
				
			}
			else {
				// Cant do this, are you crazy, ever merged without any on top?
				// Yes, you are crazy, so set the mode to own if an nestedPage exists on this current page and an 
			}
			
		}
		
		//Load Design
		if(!$this->designName) { $this->designName = $this->parentPage->designName; }
		
		if(!$this->fkPageLayoutName) {
			if(!isset($IsRootPage) || !$IsRootPage) {
				$this->fkPageLayoutName = $this->parentPage->getPageLayoutName();
			}
			else {
				//Get PageLayout from Area
				$sql = "SELECT pl.sysname FROM " . $cfg['table_prefix'] . "Area AS a
						LEFT JOIN " . $cfg['table_prefix'] . "PageLayout as pl ON pl.pkPageLayout = a.fkPageLayout
						WHERE a.pkArea = '$this->fkArea'";
				
				$this->fkPageLayoutName = $conn->quickQuery($sql);
			}
		}
		
		//Initialize the Toolbox-Lists
		$this->ItemToolbox = new ToolBoxList();
		$this->InstanceToolbox = new ToolBoxList();
		$this->ModuleToolbox = new ToolBoxList();
		$this->PageToolbox = new ToolBoxList();
		$this->SiteToolbox = new ToolBoxList();
		

	}
	
	public final function resolveNestedPages() {
		
		echo "<pre>";
		
		$conn = MySQLConnection::getInstance();
		
		//Resolve and load the Nested Pages based on the NestedPageSet of this Page and it's Parents an the NestedPageMode Setting of this Page
		
		/*
		 * Possible Modes for the current Page
		 * 
		 * Mode		Description
		 * ----		-----------
		 * NULL		Use the Parents Page NestedPageSet with Layout
		 * Merge	Merges the Parent PageSet with the one of the current Page. The Layout is inherited, only specified Pages (defined in the Pageset of the current Page) will be replaced
		 * Include	Include to NestedPageSet of the Current Page in the layout of the parent page
		 * Own		New base Layout with NestedPages.
		 */
		
		//If Mode is not 'Own', we have inherit the NestedPageSets from out Parent Pages
		if($this->nestedPageMode!='Own') {
			//Load all NestedPageSets in Array starting by the one of the Current
			
			//Build Array of all Parent Pages
			$p = $this;
			
			$parentPagesPath = array();
			while($p) {
				array_push($parentPagesPath, $p);
				$p = $p->parentPage;
			}
			//Reverse the Array (toppest Page should be index 0)
			$parentPagesPath = array_reverse($parentPagesPath);

			$startAt = 0;
			//Load the first relevant NestedPageSet (of Area if is set and) go through the PageSets of all Parent Pages
			$fkNestedPageSet = $conn->quickQuery("SELECT fkNestedPageSet FROM tblArea WHERE pkArea = %n", array($this->fkArea));
			while(!$fkNestedPageSet && $startAt < count($parentPagesPath)) {
				//Check one Page down from top
				echo "Checking page as Root-NestedPageSet '".$parentPagesPath[$startAt]->getNavTitle()."'\n";
				$fkNestedPageSet = $parentPagesPath[$startAt]->getFkNestedPageSet();
				$startAt++;
			}
			
			//Check if minimal one NestedPageSet is found
			if(!$fkNestedPageSet) {
				echo "No NestedPageSet is defined";
			}
			else {
				//Walk through
				$t = new NestedPageSetTable();
				
				//This one is set fix, all other PageSets will be merged/combined with this one.
				$parent_nps = $t->getByPkNestedPageSet($fkNestedPageSet);
				
				for($i=$startAt;$i<count($parentPagesPath);$i++) {
					
					$curr_page = $parentPagesPath[$i];
					
					$curr_nsp = $t->getByPkNestedPageSet($curr_page->getFkNestedPageSet());
					
					//If NestedPage is Include, copy settings to current Page (but do not exit loop, it might be overridden by another Include or
					
				}
			}
			
			echo "\n\nPageList\n--------\n\n";
			print_r($parentPagesPath);
			
			die();
		}
		else {
			
		}
		echo "</pre>";
		
	}
	
	public final function setPageRequest(PageRequest $pq) {
		
		$cfg = Runtime::getConfiguration();
		$conn = MySQLConnection::getInstance();
		
		$this->pageRequest = $pq;

		//Check if there is a "DesignSwitch" for this method
		$sql = "SELECT fkArea, d.sysname, disableNestedPages 
				FROM " . $cfg['table_prefix'] . "AreaSwitcher AS asw
				LEFT JOIN " . $cfg['table_prefix'] . "Area AS a ON a.pkArea = asw.fkArea
				LEFT JOIN " . $cfg['table_prefix'] . "Design AS d ON d.pkDesign = a.fkDesign
				WHERE fkMethod = '" . $this->pageRequest->getMethod() . "' AND (fkModule='$this->pkModule' OR fkModule IS NULL)
				ORDER BY fkModule DESC LIMIT 1";
		
		$data = $conn->quickQuery($sql);
	
		$this->designNameOrig = $this->designName;
		
		if($data) { 
			
			$switched = true;
			
			//echo "DesignSwitcher to $title"; 
			$this->designName = $data["sysname"];
			$this->fkArea = $data["fkArea"]; 
			
			if($data["disableNestedPages"]=="1") {
				$this->fkNestedPageSet = null;
				$this->NestedPageSet = null;
				$this->nestedPageMode = "none";
			}
		}
		else {
			$switched = false;
		}
		
		//Reload SecurityObjects, cause there is now the pageRequest available an the function is probably overriden in specialiced classes...
		$this->loadSecurityObjects();
		
		//Call here the Method, cause the must be the poisibility to override this function and add some specific methods based on the query
		$this->addPageMethods();
		
		//Check if there were set any design switches
		if(is_array($this->areaSwitches) && key_exists($pq->getMethod(), $this->areaSwitches)) {
			
			//Load switched Area from there only if no switch was set in table
			if(!$switched) {
				
				$sql = "SELECT pkArea, d.sysname 
						FROM " . $cfg['table_prefix'] . "Area AS a 
						LEFT JOIN " . $cfg['table_prefix'] . "Design AS d ON d.pkDesign = a.fkDesign
						WHERE a.sysname = '" . $this->areaSwitches[$pq->getMethod()] . "'";
				$data = $conn->quickQuery($sql);
				
				if($data) {
					$this->designName = $data["sysname"];
					$this->fkArea = $data["pkArea"]; 
					
					$this->fkNestedPageSet = null;
					$this->NestedPageSet = null;
					$this->nestedPageMode = "none";
				}			
			}
		}
		
	}

	
	protected function loadSecurityObjects() {
		
		//Page Security-Object
		$this->PageSecurityObject = new SecurityObject();
		$this->PageSecurityObject->loadSecurityObject($this->fkPageSecurityObject);
		
		//Instance-Security
		if($this->fkInstanceSecurityObject) {
			$this->InstanceSecurityObject = new SecurityObject();
			$this->InstanceSecurityObject->loadSecurityObject($this->fkInstanceSecurityObject);
		}

		//Item-Security (if given by the Module-Instance for a specified Item, an PhotoLibrary-Album as example...
		//Is set by the Method set		
	}
	
	protected function addPageMethods() {

		//Load Allowed Methods (Basic), for better Control, please implement this Function on your own Class
		//---------------------------
		if ($this->canInstanceRead())  {
			array_push($this->allowedMethods, "index");
			
			if ($this->canItemUpdate())  {
				array_push($this->allowedMethods, "edit");
			}
		}
		
		//$this->addToolboxItem(new ToolBoxItem("Vom System Abmelden", "logout.png", "?page=login&method=logout"), "site");
		
	}
	/**
	 * Adds an item to the Toolbox on the left of a page, or whereever
	 * @param ToolboxItem - Create one with New ToolboxItem($title, $link, $icon);
	 * @param $section - item | instance | module | site
	 */
	
	final function addToolboxItem(ToolBoxItem $i, $section="") {
		
		switch ($section) {
			
			case 'item':     $this->ItemToolbox->addItem($i); break;
			case 'instance': $this->InstanceToolbox->addItem($i); break;
			case 'module':   $this->ModuleToolbox->addItem($i); break;
			case 'page':     $this->PageToolbox->addItem($i); break;
			case 'site':     $this->SiteToolbox->addItem($i); break;
		}
		
	}
	
	final function hasToolboxItems() {
		return (!$this->ItemToolbox->isEmpty() || !$this->InstanceToolbox->isEmpty() || !$this->PageToolbox->isEmpty() || !$this->ModuleToolbox->isEmpty() || !$this->SiteToolbox->isEmpty());
	}
	
	final function getItemToolbox()     { return $this->ItemToolbox; }
	final function getInstanceToolbox() { return $this->InstanceToolbox; }
	final function getPageToolbox()     { return $this->PageToolbox; }
	final function getModuleToolbox()   { return $this->ModuleToolbox; }
	final function getSiteToolbox()     { return $this->SiteToolbox; }
	
	/**
	 * @return Page
	 */
	public final function getTopParent() {
		if($this->fkParentPage) {
			return $this->parentPage->getTopParent();
		}
		else {
			return $this;
		}
	}
	
	
	/**
	 *  
	 * Get all Pages below the current Page Recursive
	 * @return array
	 * 
	 */
	public final function getSubPages($fkMarkPathtoPage=0) {

		$this->isInPath = ($fkMarkPathtoPage == $this->pkPage);
		
		//Dont' load them twice
		if(!isset($this->subPages)) {

			$cfg = Runtime::getConfiguration();
			$conn = MySQLConnection::getInstance();
			
			$this->subPages = array();
			
			//Load SubPages from DB
			$sql = "SELECT p.pkPage, p.fkArea, p.fkParentPage, p.fkModuleInstance, p.fkMethod, p.params, p.fkSecurityObject, mi.fkSecurityObject, p.fkCreateUser, p.createDate, 
						p.fkNestedPageSet, p.nestedPageMode, p.navTitle, p.sortId, p.navImage, p.pageTitle, p.isNavVisible, tablePostfix, m.pkModule, m.name, d.sysname, 
						p.fkPageLayout, pl.sysname AS  fkPageLayoutName
					FROM " . $cfg['table_prefix'] . "Page as p
					LEFT JOIN " . $cfg['table_prefix'] . "ModuleInstance as mi ON mi.pkModuleInstance = p.fkModuleInstance
					LEFT JOIN " . $cfg['table_prefix'] . "Module as m ON m.pkModule = mi.fkModule
					LEFT JOIN " . $cfg['table_prefix'] . "Area as a ON a.pkArea = p.fkArea
					LEFT JOIN " . $cfg['table_prefix'] . "Design as d ON d.pkDesign = a.fkDesign
					LEFT JOIN " . $cfg['table_prefix'] . "PageLayout as pl ON pl.pkPageLayout = p.fkPageLayout
									
					WHERE fkParentPage='$this->pkPage'
					ORDER BY sortId ASC";
			$res = $conn->query($sql);
	
			while(($data = mysql_fetch_array($res))) {
				
				$p = new Page($data['pkPage'], $this, $data);
				$p->getSubPages($fkMarkPathtoPage);
				
				//Check ig Child is in Path, parent must be in Path too
				if($p->getIsInPath()) { $this->isInPath = $p->getIsInPath(); }

				array_push($this->subPages, $p);
			}			
		}
		

				
		return $this->subPages;
	}
	
	public final function hasSubPages() {
		$this->getSubPages();
		return count($this->subPages)>0;	

	}
	
	/**
	 * Set if this Page is in the Path to the Target Site (current Processed) Page
	 * @return void
	 */
	public final function markAsPathNode() {
		$this->isInMenuPath = true;
	}
	
	
	//PageMethods
	//===========
	
	//Cannot be overridden, because you should change the allowedMethods-Array to change acces privilegues
	
	public final function allowMethod($name, $switchToArea=null) {
		
		array_push($this->allowedMethods, $name);
		
		if($switchToArea!=null) {
			$this->addAreaSwitch($name, $switchToArea);
		}
		
	}
	
	public final function addAreaSwitch($method, $area) {
		if(!is_array($this->areaSwitches)) { $this->areaSwitches = array(); }
		
		$this->areaSwitches[$method] = $area;
	}
	
	public final function canInvokeMethod($name) {
		//Check if name is listed in $availableMethods
		$m = array_map('strtolower', $this->allowedMethods);
		
		return $this->canItemRead() && in_array(strtolower($name), $m);
	}
	
	public final function getPageMethods() {
		
		return $this->pageMethods();
		
	}
	
	
	/*
	 * ===================================================
	 * 				    GETTERS FUNCTIONS
	 * 				    -----------------
	 * 
	 * All these functions should be overvritten in more
	 * specaliced types of Page
	 * ===================================================
	 */

	//Contentz based Information
	public final function getText()       { return $this->pageText; }
	public final function getTitle()      { return $this->pageTitle; }
	public final function getTitleImage() { return new ImageTexter($this->pageTitle, $this->getSetting("TitleSize", 12), $this->getSetting("TitleFont", "Arial"), $this->getSetting("TitleColor", "0x000000")); }
	public final function getCreateUser() { return $this->pageCreateUser; }
	public final function getCreateDate() { return $this->pageCreateDate; }
	public final function getChangeUser() { return $this->pageChangeUser; }
	public final function getChangeDate() { return $this->pageChangeDate; }
	public final function getPlaintext()  { return $this->pageText; }
	
	public function getCreateUserName() { 
		return MySQLConnection::getInstance()->quickQuery("SELECT uname FROM tblSecurityUser WHERE pkSecurityUser='$this->pageCreateUser'");
	}
	
	public function getCreateUserFullName() { 
		return MySQLConnection::getInstance()->quickQuery("SELECT realname FROM tblSecurityUser WHERE pkSecurityUser='$this->pageCreateUser'");
	}
	
	public function getChangeUserName() { 
		return MySQLConnection::getInstance()->quickQuery("SELECT uname FROM tblSecurityUser WHERE pkSecurityUser='$this->pageChangeUser'");
	}
	
	public function getChangeUserFullName() { 
		return MySQLConnection::getInstance()->quickQuery("SELECT realname FROM tblSecurityUser WHERE pkSecurityUser='$this->pageChangeUser'");
	}
	
	//Page Acces (Menu Permission Control)
	public final function canPageCreate()		  { return $this->PageSecurityObject->canCreate(); } 		//Can ad new Pages unter this Page as child
	public final function canPageRead()  		  { return $this->PageSecurityObject->canRead(); }			//Can Navigation Item be read?
	public final function canPageUpdate() 		  { return $this->PageSecurityObject->canUpdate(); }		//Can Update the Nabigation Item, ModuleInstance, Title, NavTitle, ...
	public final function canPageDelete()		  { return $this->PageSecurityObject->canDelete(); }		//Can Delete the Naviation Item (only if alle Subtems also can be deleted)
	public final function canPageAdmin()		  { return $this->PageSecurityObject->canAdmin(); }			//Can Manage the Permissions of the Nav-Entry
	public final function getPageSecurityObject() { return $this->PageSecurityObject; }
	
	//Page Instance Acces (Acces to the Page Item itself), Security Object is loaded by the instance of the spacialiced class itself
	public final function canInstanceCreate()	  { return (isset($this->InstanceSecurityObject)?$this->InstanceSecurityObject->CanCreate():$this->PageSecurityObject->canCreate()); }	//Can Create new Items in this Instance
	public final function canInstanceRead()  	  { return (isset($this->InstanceSecurityObject)?$this->InstanceSecurityObject->CanRead()  :$this->PageSecurityObject->canRead()); }		//Can read the contents of the Instance
	public final function canInstanceUpdate() 	  { return (isset($this->InstanceSecurityObject)?$this->InstanceSecurityObject->canUpdate():$this->PageSecurityObject->canUpdate()); }	//Can Update the Item
	public final function canInstanceDelete() 	  { return (isset($this->InstanceSecurityObject)?$this->InstanceSecurityObject->canDelete():$this->PageSecurityObject->canDelete()); }	//Can Delete the Item
	public final function canInstanceAdmin()  	  { return (isset($this->InstanceSecurityObject)?$this->InstanceSecurityObject->canManage():$this->PageSecurityObject->canManage()); }	//Can Manage Permissions on the Instance
	
	//Acces to an Item in the Page Itself, the Item is managed by the Module, but the page should no be accessible if, the Item is not readable for example.
	public final function canItemCreate()		  { return (isset($this->ItemSecurityObject)?$this->ItemSecurityObject->CanCreate():$this->canInstanceCreate()); }	//Can Create new Items in this Instance
	public final function canItemRead()  		  { return (isset($this->ItemSecurityObject)?$this->ItemSecurityObject->CanRead()  :$this->canInstanceRead()); }		//Can read the contents of the Instance
	public final function canItemUpdate() 		  { return (isset($this->ItemSecurityObject)?$this->ItemSecurityObject->canUpdate():$this->canInstanceUpdate()); }	//Can Update the Item
	public final function canItemDelete() 		  { return (isset($this->ItemSecurityObject)?$this->ItemSecurityObject->canDelete():$this->canInstanceDelete()); }	//Can Delete the Item
	public final function canItemAdmin()  		  { return (isset($this->ItemSecurityObject)?$this->ItemSecurityObject->canManage():$this->canInstanceManage()); }	//Can Manage Permissions on the Instance
	
	
	public final function getPkPage()           { return $this->pkPage; } 
	public final function getFkArea()           { return $this->fkArea; } 
	public final function getFkModule()         { return $this->pkModule; }
	/**
	 * Returns the Parent Page if the current Page (if exists)
	 *
	 * @return Page
	 */
	public final function getParentPage()		{ return $this->parentPage; }
	public final function getModuleName()		{ return $this->moduleName; }
	public final function getMethod()	 		{ return ($this->pageRequest?$this->pageRequest->getMethod():$this->moduleMethod); }
	public final function getParams()			{ return $this->params; }
	public final function getFkModuleInstance() { return $this->fkModuleInstance; }
	
	private final function getFkNestedPageSet() { return $this->fkNestedPageSet; }
	/**
	 * Returns the PageSet of the Page
	 *
	 * @return NestedPageSet
	 */
	public final function getNestedPageSet()   { return $this->NestedPageSet; }
	public final function getNestedPageMode()  { return $this->nestedPageMode; }
	
	public final function getDesignName()		{ return $this->designName; }
	public final function getDesignNameOrig()	{ return $this->designNameOrig; }
	public final function getDesignMode()		{ return $this->designMode; }
	public final function setDesignMode($v)		{ $this->designMode = $v; }	
	
	public final function getPageLayoutName()   { return $this->fkPageLayoutName; }
	public final function getNavTitle() 		{ return $this->navTitle; }
	public final function getNavImage()			{ return $this->navImage; }
	public final function getIsNavVisible() 	{ return $this->isNavVisible;}
	public final function getIsInPath() 		{ return $this->isInPath; }
	public final function getIsPlainText() 		{ return $this->isPlainText; }
	
	public final function getUrl()				{ 
		return count($this->subPages)?"#":"?page=$this->pkPage".
			   ($this->moduleMethod?"&amp;method=".$this->moduleMethod:"").
			   ($this->params?"&amp;".$this->params:""); }
	
	
	//Like a getter Function
	public final function getSetting($name, $default=null) {
		$val = Runtime::getSetting($name, $this->pkModule, $this->fkModuleInstance);
		if($val=="" && isset($default)) { $val = $default; }
		return $val;
	}
	
	//Get path (relative to root) to the data of the Page. Create it, if it doas not exist
	public final function getDataDir($folder=null) {

		$cfg = Runtime::getConfiguration();
		
		//Create Base-Dir for Module-Data
		$dir = $cfg['paths']['page'] . "/content/module";
		$folder = $this->getModuleName() . "/" . $folder;
		

		$folder = str_replace("\\", "/", $folder);
		$folders = split("/", $folder);
		
		
		for($i=0;$i<sizeof($folders);$i++) {
			
			//Create Subfolder if not exists
			$dir.= "/" . $folders[$i];
			if(!file_exists($dir)) {
				$old_umask = umask(0);
				mkdir($dir,0777); // the default chmod
				umask($old_umask);
			}
			
		}
		
		return $dir; 
	}
	
	public final function getDataPath() {
		return "content/module/".$this->getModuleName();
	}
	
	
	public final function logEvent($friendly, $file, $classname, $function, $line, $vardata="") {
		
		logger::logEvent($friendly, $file, $classname, $function, $line, $vardata, $this);		
	}
	
	/*
	 * ===================================================
	 * 					CONTENT FUNCTIONS
	 * 					-----------------
	 * 
	 * ===================================================
	 */
	
	public final function assignDataToSmarty(Smarty $s) {
		
		$s->assign("Page_Title", $this->pageTitle);
		$s->assign("Page_Text",  $this->pageText);
		
		$s->assign("Page_CreateUser",  $this->pageCreateUser);
		$s->assign("Page_CreateDate",  $this->pageCreateDate);
		$s->assign("Page_CreateUserRealname", $this->getCreateUserFullName());
		
		$s->assign("Page_ChangeUser",  $this->pageChangeUser);
		$s->assign("Page_ChangeDate",  $this->pageChangeDate);
		$s->assign("Page_ChangeUserRealname", $this->getCreateUserFullName());

		$s->assign("Page_NavTitle", $this->getNavTitle());
		
		$this->assignCustomDataToSmarty($s);	
		
	}
	
	//Better way to do this
	public function addViewData($var, $data) {
		
		$this->viewData[$var] = $data;
		
	}
	
	public function getViewData($var=null) {
		if($var) {
			return $this->viewData[$var];
		}
		else {
			return $this->viewData;
		}
	}
	
	protected function setJsonResponse($value) {
		$this->isPlainText = true;
		$this->pageText = json_encode($value);
	}
	
	protected final function setAjaxResponse($value=null) {
		if($value) {
			$this->pageText = $value;
		}
		
		$this->designMode = "ajax";
	}
	
	protected final function disableNestedPages() {
		$this->nestedPageMode = "Own";
		$this->NestedPageSet = array();
	}
	
	//Very BAAAAD Way to do this
	public function assignCustomDataToSmarty(Smarty $s) {
		//Override this Method
		
		$s = $s;
	}  
	
	
	
	
	
	
	
	
	
	
	
	//Methods, should be overriden
	public function index() {
		//Override this Method
		
		//Nothing Happens here;
		
		$this->pageText = "Error! Index not implemented in the specialized Class!";
	}

	
}

?>